//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<Style.cpp>
///	@path	~/src/gui/style/
///	@date	2008/10/19
///	@desc	.

#define _FULLAPI
#include "config/config.h"

#include <set>

#include "lib/system/sysinfo.h"
#include "lib/utilities/observer.h"

#include "gui/style/style.h"

static int s_FontFamilyCount = 0;
static int s_FontLoadedCount = 0;
static size_t s_FontMemorySize = 0;

namespace xeres {

	/*!	
		\class	StyleFontFamily
		\brief	Internal font family encapsulation.
	*/
	class StyleFontFamily
	{
	public:

		/// \ctor
		StyleFontFamily( const WString& name )
			: m_name( name )
		{
			// update statistics
			OBSERVE_STAT( ++s_FontFamilyCount );
		}

		/// \dtor
		~StyleFontFamily( void )
		{
			// update statistics
			OBSERVE_STAT( --s_FontFamilyCount );
		}
		//	Font family will hash fonts to store in a map, recognizes different font sets.
		//
		//  [ 32 ~ 17 (15) ]   [ 16 ~ 6 (10) ]   [  5  ]	[  4  ]
		//    height		      weight          italic       aa

		/// \brief	Hash font info.
		static uint HashFont( int height , int weight , int italic , int antialias )
		{
			XS_ASSERT( height < 0x8000 /*32768*/ );
			XS_ASSERT( weight < 0x3ff /*1024*/ );
			XS_ASSERT( italic == 0 || italic == 1 );
			XS_ASSERT( antialias == 0 || antialias == 1 );
			uint hash = (height << 15) | (weight << 6) | (italic<<5) | (antialias<<4);
			return hash;
		}

		/// \brief	Get subset.
		RefWeak<StyleFont> GetSubset( int height , int weight , bool italic , bool antialias )
		{
			uint hash = HashFont( height , weight , int(italic) , int(antialias) );
			std::map< uint,RefWeak<StyleFont> >::iterator it
				= m_subset.find( hash );
			if( it == m_subset.end() )
			{
				// update statistics
				OBSERVE_STAT( ++s_FontLoadedCount );

				// create new subset
				StyleFont * newFont = new StyleFont( this , m_name , height , weight , italic , antialias );
				if( newFont->hfont() == NULL )
					return NULL;

				m_subset[ hash ] = newFont;
				return newFont;
			}
			return it->second;
		}

		/// \brief	Get name.
		const WString& GetName( void ) const
		{
			return m_name;
		}

		/// \brief	Delete Font.
		void DeleteFont( RefWeak<StyleFont> font )
		{
			uint hash = HashFont( font->GetLogicHeight() , font->GetWeight() , int(font->GetItalic()) , int(font->GetAntialias()) );
			std::map< uint,RefWeak<StyleFont> >::iterator it
				= m_subset.find( hash );
			XS_ASSERT( it != m_subset.end() );
			m_subset.erase( it );

			// update statistics
			OBSERVE_STAT( --s_FontLoadedCount );
		}

	private:

		//@ data
		WString m_name;
		std::map< uint , RefWeak<StyleFont> > m_subset;
	};

	namespace
	{
		/*! 
			\class	FontMap
			\brief	Stores all loaded font families.
		*/
		class FontMap
		{
		private:

			/// \ctor
			FontMap( void )
			{
				OBSERVE_WATCH( _S("ui/Fonts/Families : Font Family Count       ") , s_FontFamilyCount );
				OBSERVE_WATCH( _S("ui/Fonts/Loaded   : Fonts Loaded            ") , s_FontLoadedCount );
				OBSERVE_WATCH( _S("ui/Fonts/DataSize : Font Data Memory Size   ") , s_FontMemorySize );
			}

			/// \dtor
			~FontMap( void )
			{
				for( dict<WString,StyleFontFamily*>::iterator it = m_fontMap.begin() , end = m_fontMap.end() ;
					it != end ; ++it )
				{
					delete it->second;
				}	
			}

		public:

			/// \instance
			static FontMap& instance( void )
			{
				static FontMap s_fontMap;
				return s_fontMap;
			}

			/// \brief Get font family.
			StyleFontFamily * GetFontFamily( const WString& fontname )
			{
				dict<WString,StyleFontFamily*>::iterator it =
					m_fontMap.find( fontname );
				if( it == m_fontMap.end() )
				{
					StyleFontFamily * newSet = new StyleFontFamily( fontname );
					m_fontMap[ fontname ] = newSet;
					return newSet;
				}
				return it->second;
			}

		private:

			//@ data
			dict<WString,StyleFontFamily*>	m_fontMap;
		};
	}
	
	IMPL_IOBJECT_CLASS( StyleFont );

	// StyleFont
	StyleFont::StyleFont( StyleFontFamily * family , const WString& name , int height , int weight , bool itatlic , bool antialias )
		: m_family( family )
		, m_height( height )
		, m_weight( weight )
		, m_ascent( 0 )
		, m_descent( 0 )
		, m_baseline( 0 )
		, m_maxCharWidth( 0 )
		, m_space( 0 )
		, m_italic( itatlic )
		, m_antialias( antialias )
		, m_font( NULL )
		, m_oldFont( NULL )
		, m_sprite( NULL )
		, m_oldBitmap( NULL )
		, m_buffer( NULL )
		, m_hdc( NULL )
		, m_fontDataSize( 0 )
	{
		TEXTMETRIC tm;
		DWORD charset = DEFAULT_CHARSET;
		DWORD quality = DEFAULT_QUALITY;
		if( antialias )
		{
			quality = ANTIALIASED_QUALITY;
			if( get_system_version() >= 5001 )
				quality = CLEARTYPE_NATURAL_QUALITY;
		}

		const wchar_t * fontname = name.c_str();
		m_font = ::CreateFont( -m_height , 0 , 0 , 0 , m_weight ,
			(DWORD)m_italic , 0 , 0 , charset ,
			OUT_TT_PRECIS , CLIP_DEFAULT_PRECIS , quality , DEFAULT_PITCH | FF_DONTCARE , fontname );

		if( m_font != NULL )
		{
			HDC ddc = ::GetWindowDC( NULL );
			m_hdc =::CreateCompatibleDC( ddc );
			XS_ASSERT( m_hdc != NULL );
			::ReleaseDC( NULL , ddc );

			m_oldFont = (HFONT)::SelectObject( m_hdc , m_font );
			if( ::GetTextMetrics( m_hdc ,&tm ) == FALSE )
			{
				__win32_error( _S("StyleFont::StyleFont: GetTextMetrics error : %s") );
				// use default font

				::SelectObject( m_hdc , m_oldFont );
				::DeleteDC( m_hdc );
				::DeleteObject( m_font );
				m_hdc = NULL;
				m_oldFont = NULL;
				m_font = NULL;
				return;
			}
		}
		else
		{
			return;
		}

		// Settings.
		::SetTextColor( m_hdc , RGB(255,255,255) );
		::SetBkColor( m_hdc , 0 );
		::SetBkMode( m_hdc , OPAQUE );

		int w = tm.tmMaxCharWidth + 3;
		int h = tm.tmHeight;

		// Create font bitmap cache.
		BITMAPINFO bmi = {0};
		bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
		bmi.bmiHeader.biWidth       = w;
		bmi.bmiHeader.biHeight      = h;
		bmi.bmiHeader.biPlanes      = 1;
		bmi.bmiHeader.biBitCount    = 32;
		bmi.bmiHeader.biCompression = BI_RGB;
		bmi.bmiHeader.biSizeImage   = bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight * 4;

		m_sprite = CreateDIBSection( m_hdc , &bmi , DIB_RGB_COLORS, (void**)&m_buffer, NULL, 0 );
		m_oldBitmap = (HBITMAP)::SelectObject( m_hdc , m_sprite );
		m_spritePitch = w * 4;

		// make kerning pairs
		DWORD pairs = ::GetKerningPairs( m_hdc , 0 , NULL );
		if( pairs > 0 )
		{
			KERNINGPAIR * kp = new KERNINGPAIR[ pairs ];
			::GetKerningPairs( m_hdc , pairs , kp );
			for( DWORD i = 0 ; i < pairs ; ++i )
				m_kernPairs[(kp[i].wFirst<<16)|kp[i].wSecond] = kp[i].iKernAmount;
			delete [] kp;
		} 

		m_fontheight = tm.tmHeight;
		m_ascent = tm.tmAscent;
		m_descent = tm.tmDescent;
		m_baseline = m_fontheight - m_descent;
		m_internalLeading = tm.tmInternalLeading;
		m_externalLeading = tm.tmExternalLeading;
		m_maxCharWidth = tm.tmMaxCharWidth;
	}
	// ~StyleFont
	StyleFont::~StyleFont( void )
	{
		if( m_hdc )
		{
			::SelectObject( m_hdc , m_oldBitmap );
			::SelectObject( m_hdc , m_oldFont );
			::DeleteDC( m_hdc );
		}
		if( m_sprite )
		{
			::DeleteObject( m_sprite );
		}
		if( m_font )
		{
			::DeleteObject( m_font );
		}

		for( std::map<int,FontChar*>::iterator it = m_chars.begin() , end = m_chars.end() ;
			it != end ; ++it )
		{
			free( it->second );
		}
		OBSERVE_STAT( s_FontMemorySize -= m_fontDataSize );
		if( m_family )
		{
			m_family->DeleteFont( this );
		}
	}
	namespace
	{
		std::set< WString > s_allFonts;

		// Enum Font Proc
		static int CALLBACK EnumFonts( CONST ENUMLOGFONTEX * lpelfe , CONST NEWTEXTMETRICEX * lpntme , DWORD FontType , LPARAM lParam )
		{
			if( FontType == TRUETYPE_FONTTYPE || FontType == RASTER_FONTTYPE )
			{
				s_allFonts.insert( WString( lpelfe->elfFullName ) );
				//TRACE_INFO( _S("Enum font '%s'.") , lpelfe->elfFullName );
			}
			return TRUE;
		}
	}
	// QueryFont
	bool StyleFont::QueryFont( const WString& name )
	{
		if( s_allFonts.empty() )
		{
			LOGFONT logFont;
			memset( &logFont , 0 , sizeof(LPLOGFONT) );
			logFont.lfFaceName[0] = '\0';
			logFont.lfCharSet = DEFAULT_CHARSET;
			HDC hdc = ::CreateCompatibleDC( NULL );
			::EnumFontFamiliesEx( hdc, &logFont, (FONTENUMPROC)EnumFonts , NULL, 0 );
		}
		return s_allFonts.find( name ) != s_allFonts.end();
	}
	// InstallFont
	bool StyleFont::InstallFont( const WString& file )
	{
		if( ::AddFontResourceEx( file.c_str() , FR_PRIVATE , 0 ) == 0 )
		{
			__win32_error( _S("StyleFont::InstallFont: Failed to install font resource: %s") );
			return false;
		}
		s_allFonts.clear();
		return true;
	}
	namespace
	{
		/*! 
			\class	LoadedFonts
			\brief
		*/
		class LoadedFonts
		{
		public:

			/// \instance
			static LoadedFonts& instance( void )
			{
				static LoadedFonts s_loadedFontsInstance;
				return s_loadedFontsInstance;
			}

			/// \brief	Add loaded font.
			void AddLoadedFont( HANDLE loaded )
			{
				m_loadedFonts.insert( loaded );
			}

		private:

			/// \dtor
			~LoadedFonts( void )
			{
				for( std::set<HANDLE>::iterator it = m_loadedFonts.begin() , end = m_loadedFonts.end() ;
					it != end ; ++it )
				{
					::RemoveFontMemResourceEx( *it );
				}
			}

			// @data
			std::set<HANDLE> m_loadedFonts;
		};
	}
	// InstallFontFromMemory
	bool StyleFont::InstallFontFromMemory( const WString& file , void * data , size_t size )
	{
		DWORD count = 0;
		HANDLE loaded = ::AddFontMemResourceEx( data , size , 0 , &count );
		if( loaded == INVALID_HANDLE_VALUE )
		{
			__win32_error( _S("StyleFont::InstallFont: Failed to install font resource: %s") );
			return false;
		}
		s_allFonts.clear();
		// Register loaded resource.
		LoadedFonts::instance().AddLoadedFont( loaded );
		return true;
	}
	// CreateFont
	Ref<StyleFont> StyleFont::CreateFont( const WString& name /*= _S("") */, int height /*= 12 */, int weight /*= 400 */, bool italic /*= false */, bool antialias /*= false */ )
	{
		const wchar_t * fontname = name.c_str();
		if( name == _S("") )
			fontname = _S("Tahoma");
		return FontMap::instance().GetFontFamily( fontname )->GetSubset( height , weight , italic , antialias );
	}
	// GetName
	const WString& StyleFont::GetName( void ) const
	{
		return m_family->GetName();
	}
	// GetCharacter
	StyleFont::FontChar * StyleFont::GetCharacter( int c )
	{
		std::map<int,FontChar*>::iterator it = m_chars.find( c );
		if( it == m_chars.end() )
		{
			FontChar * ch = CreateCharacter( c );
			m_chars[c] = ch;
			return ch;
		}
		return it->second;
	}
	// CreateCharacter
	StyleFont::FontChar * StyleFont::CreateCharacter( int c )
	{
		TEXTMETRIC tm;
		::GetTextMetrics( m_hdc , &tm );

		DWORD size;
		static MAT2 mat2 = {{0,1},{0,0},{0,0},{0,1}};
		GLYPHMETRICS gm;
		size = ::GetGlyphOutline(
			m_hdc ,
			c ,
			GGO_GRAY8_BITMAP ,
			&gm ,
			0 ,
			NULL ,
			&mat2 );

		if( size > 0 )
		{
			wchar_t ch( c );

			// Calculate proper width.
			HDC dc = ::GetWindowDC( NULL );
			HFONT of = (HFONT)::SelectObject( dc , m_font );
			RECT rt;
			::SetBkColor( dc , 0 );
			::DrawText( dc , &ch , 1 , &rt , DT_EDITCONTROL | DT_SINGLELINE | DT_NOPREFIX | DT_LEFT | DT_TOP | DT_CALCRECT );

			ABC abc;
			::GetCharABCWidths( dc , ch , ch , &abc );

			SIZE sz = {0};
			BOOL result = ::GetTextExtentPoint32( dc , &ch , 1 , &sz );
			int w = rt.right - rt.left;
			int h = rt.bottom - rt.top;
			w = max<int>( w , sz.cx );
			int step = w;
			if( abc.abcC < 0 )
				w -= abc.abcC;
			size = sizeof(uint) * w * h;

			::SelectObject( dc , of );
			::ReleaseDC( NULL , dc );

			byte * pb = m_buffer;
			RECT rc = { 0 , 0 , w , h };

			// Draw to buffer.
			::SetBkColor( m_hdc , 0 );
			::DrawText( m_hdc , &ch , 1 , &rc , DT_SINGLELINE | DT_LEFT | DT_TOP | DT_NOPREFIX );

			FontChar * data = CreateFontData( size );
			OBSERVE_STAT( ++s_FontMemorySize );

			uint * xb = (uint*)data->m_buffer;
			byte * tb = NULL;

			for( int y = 0 ; y < h ; ++y )
			{
				tb = ( pb + ( h - y - 1 ) * m_spritePitch );
				for( int x = 0 ; x < w ; ++x , tb += 4 )
				{
					uint * dst = xb + ( x + y * w );

					uint er = tb[2];
					uint eg = tb[1];
					uint eb = tb[0];

					uint sum = er + eg + eg + eb;
 					sum = sum >> 2;

					*dst = ((sum)<<24) | ((er)<<16) | ((eg)<<8) | (eb);
				}
			}
			data->m_width = w;
			data->m_step = step;
			data->m_aWidth = abc.abcA;
			data->m_cWidth = abc.abcC;
			return data;
		}
		else
		{
			FontChar * data = CreateFontData( 0 );
			data->m_width = 0;
			data->m_step = gm.gmCellIncX;
			return data;
		}
	}
	// GetPairs
	int StyleFont::GetPairs( wchar_t c1 , wchar_t c2 )
	{
		uint key = ((c1<<16)|c2);
		std::map<uint,int>::iterator it = m_kernPairs.find( key );
		if( it != m_kernPairs.end() )
			return it->second;
		return 0;
	}
	// CreateFontData
	StyleFont::FontChar * StyleFont::CreateFontData( size_t chunk_size )
	{
		size_t size = ALIGNOF( ( sizeof(FontChar) - sizeof(uchar) + chunk_size ) , 16 );
		m_fontDataSize += size;
		OBSERVE_STAT( s_FontMemorySize += m_fontDataSize );
		FontChar * data = (FontChar*)malloc( size );
		return data;
	}

	// PlacementStyle
	PlacementStyle::PlacementStyle( void )
		: m_horizontal( LEFT )
		, m_vertical( TOP )
		, m_padding( 0 )
		, m_padding_left( 0 )
		, m_padding_top( 0 )
		, m_padding_right( 0 )
		, m_padding_bottom( 0 )
		, m_margin( 0 )
		, m_margin_left( 0 )
		, m_margin_top( 0 )
		, m_margin_right( 0 )
		, m_margin_bottom( 0 )
	{
	}
	// PlacementStyle
	PlacementStyle::PlacementStyle( const PlacementStyle& rhs )
		: m_horizontal( rhs.m_horizontal )
		, m_vertical( rhs.m_vertical )
		, m_padding( rhs.m_padding )
		, m_padding_left( rhs.m_padding_left )
		, m_padding_top( rhs.m_padding_top )
		, m_padding_right( rhs.m_padding_right )
		, m_padding_bottom( rhs.m_padding_bottom )
		, m_margin( rhs.m_margin )
		, m_margin_left( rhs.m_margin_left )
		, m_margin_top( rhs.m_margin_top )
		, m_margin_right( rhs.m_margin_right )
		, m_margin_bottom( rhs.m_margin_bottom )
	{
	}

	// GetImageCoord
	Pair<int> PlacementStyle::GetImageCoord( const Pair<int>& size , const Rect<int>& place )
	{
		int left = place.left();
		int top = place.top();
		int right = place.right();
		int bottom = place.bottom();

		int pad_left = m_padding_left == 0 ? m_padding : m_padding_left;
		int pad_top = m_padding_top == 0 ? m_padding : m_padding_top;
		int pad_right = m_padding_right == 0 ? m_padding : m_padding_right;
		int pad_bottom = m_padding_bottom == 0 ? m_padding : m_padding_bottom;

		left += pad_left;
		top += pad_top;
		right -= pad_right;
		bottom -= pad_bottom;

		if( left > right || top > bottom )
			return Pair<int>(0,0);

		Rect<int> img( left , top , right , bottom );

		int x = left;
		int y = top;
		
		switch( m_horizontal )
		{
		case LEFT:
			break;
		case MIDDLE:
			x += img.width() / 2 - size.x / 2;
			break;
		case RIGHT:
			x = img.right() - size.x;
			break;
		}

		switch( m_vertical )
		{
		case TOP:
			break;
		case CENTER:
			y += img.height() / 2 - size.y / 2;
			break;
		case BOTTOM:
			y = img.bottom() - size.y;
			break;
		}
		return Pair<int>( x , y );
	}

	// GetStyles
	const std::vector<WString>& PlacementStyle::GetStyles( void )
	{
		static const std::vector<WString> s_styles;
		if( s_styles.empty() )
		{
		}
		return s_styles;
	}

	// TextStyle
	TextStyle::TextStyle( void )
		: m_font( StyleFont::CreateFont() )
		, m_textColor( 0xffffffff )
		, m_edgeColor( 0x0 )
		, m_shadowColor( 0x0 )
		, m_textBackColor( 0x0 )
		, m_decoration( DECORATION_NONE )
		, m_lineHeight( 0 )
		, m_textIndent( 0 )
		, m_textOffset( 0 , 0 )
		, m_textLetterSpacing( 0 )
		, m_textWordSpacing( 0 )
		, m_textTransform( LETTER_NORMAL )
	{
	}
	// TextStyle
	TextStyle::TextStyle( const TextStyle& rhs )
		: m_font( rhs.m_font )
		, m_textColor( rhs.m_textColor )
		, m_edgeColor( rhs.m_edgeColor )
		, m_shadowColor( rhs.m_shadowColor )
		, m_textBackColor( rhs.m_textBackColor )
		, m_decoration( rhs.m_decoration )
		, m_lineHeight( rhs.m_lineHeight )
		, m_textIndent( rhs.m_textIndent )
		, m_textOffset( rhs.m_textOffset )
		, m_textLetterSpacing( rhs.m_textLetterSpacing )
		, m_textWordSpacing( rhs.m_textWordSpacing )
		, m_textTransform( rhs.m_textTransform )
	{
	}
	static bool inline _isspace( int c )
	{
		return c == ' ' || c == '\t';
	}
	// ArrangeText
	int TextStyle::ArrangeText( const wchar_t * text , int len , int * arrangement , wchar_t prev , int * width )
	{
		if( len == 0 )
			return 0;

		// fix length
		size_t slen = wcslen( text );
		if( len < 0 )
			len = int(slen);
		else
			len = min<int>( len , slen );

		// First char.
		arrangement[0] = 0;

		int last = GetLetter( text[0] , prev );
		int start = m_font->GetCharacter( last )->m_step;

		// Calculate all one by one
		for( int i = 1 ; i < len ; ++i )
		{
			int c = GetLetter( text[i] , last );
			StyleFont::FontChar * ch = m_font->GetCharacter( c );

			// determine if it's the end of a word
			if( !_isspace( last ) && _isspace( c ) )
			{
				// Word spacing.
				start += m_textWordSpacing;
			}

			// Letter spacing.
			start += m_textLetterSpacing;

			// Assign to arrangement
			arrangement[i] = start;

			// Step inc.
			start += ch->m_step;
			
			last = c;
		}
		if( width )
			*width = start;

		return len;
	}
	// ArrangeText
	int TextStyle::ArrangeText( const wchar_t * text , int len , int * arrangement , int width_limit , wchar_t prev , int * width , int ident , bool break_endl )
	{
		if( len == 0 )
			return 0;

		// fix length
		size_t slen = wcslen( text );
		if( len < 0 )
			len = int(slen);
		else
			len = min<int>( len , slen );

		// First char.

		int last = GetLetter( text[0] , prev );
		int start = ident;
		int next = ident + m_font->GetCharacter( last )->m_step;

		// Calculate all one by one
		for( int i = 0 ; i < len ; ++i )
		{
			// check limit
			if( next > width_limit )
			{
				if( width )
					*width = start;
				return i;
			}

			int c = GetLetter( text[i] , last );

			// disable '\r' of end line
			XS_ASSERT( c != '\r' );

			// Determine break
			if( break_endl && c == '\n' )
			{
				if( width )
					*width = start;
				return i;
			}

			// Assign to arrangement
			arrangement[i] = start;
			start = next;

			StyleFont::FontChar * ch = m_font->GetCharacter( c );

			// determine if it's the end of a word
			if( !_isspace( last ) && _isspace( c ) )
			{
				// Word spacing.
				start += m_textWordSpacing;
			}

			// Letter spacing.
			start += m_textLetterSpacing;

			// Step inc.
			next = start + ch->m_step;
			
			last = c;
		}
		if( width )
			*width = start;

		return len;
	}

	// GetLetter
	int TextStyle::GetLetter( int c , int last ) const
	{
		if( !isalpha(c) )
			return c;

		switch( m_textTransform )
		{
		case LETTER_NORMAL:
			return c;
		case CAPITALIZE:
			if( _isspace(last) )
				return toupper(c);
			return c;
		case UPPERCASE:
			return toupper(c);
		case LOWERCASE:
			return tolower(c);
		}
		return c;
	}
	// NeedRearrange
	bool TextStyle::NeedRearrange( const TextStyle& rhs ) const
	{
		if( rhs.m_font != m_font )
			return true;
		if( rhs.m_lineHeight != m_lineHeight )
			return true;
		if( rhs.m_textIndent != m_textIndent )
			return true;
		if( rhs.m_textLetterSpacing != m_textLetterSpacing )
			return true;
		if( rhs.m_textWordSpacing != m_textWordSpacing )
			return true;
		if( rhs.m_textTransform != m_textTransform )
			return true;
		return false;
	}
	// ImageStyle
	ImageStyle::ImageStyle( void )
		: m_tint( 0x0 )
		, m_filter( 0x0 )
		, m_borderColor( 0x0 )
	{
	}

	// ImageStyle
	ImageStyle::ImageStyle( const ImageStyle& rhs )
		: m_tint( rhs.m_tint )
		, m_filter( rhs.m_filter )
		, m_borderColor( rhs.m_borderColor )
	{
	}

	IMPL_IOBJECT_INTERFACE( IStyle );

	// IStyle
	IStyle::IStyle( void )
	{
	}
	// ~IStyle
	IStyle::~IStyle( void )
	{
	}

	IMPL_IOBJECT_CLASS_DYNAMIC( CTextStyle );

	// CTextStyle
	CTextStyle::CTextStyle( void )
	{

	}
	// CTextStyle
	CTextStyle::CTextStyle( const CTextStyle& rhs )
	{
		*((PlacementStyle*)this) = rhs;
		*((TextStyle*)this) = rhs;
	}
	// ~CTextStyle
	CTextStyle::~CTextStyle( void )
	{

	}
	// QueryStyle
	RefWeak<IVar> CTextStyle::QueryStyle( const WString& name )
	{
		return NULL;
	}
	// SetStyle
	bool CTextStyle::SetStyle( const WString& name , const WString& value )
	{
		return false;
	}

	IMPL_IOBJECT_CLASS_DYNAMIC( CImageStyle );

	// CImageStyle
	CImageStyle::CImageStyle( void )
	{

	}
	// ~CImageStyle
	CImageStyle::~CImageStyle( void )
	{

	}
	// QueryStyle
	RefWeak<IVar> CImageStyle::QueryStyle( const WString& name )
	{
		return NULL;
	}
	// SetStyle
	bool CImageStyle::SetStyle( const WString& name , const WString& value )
	{
		return false;
	}
	
} // namespace xeres
